package com.jic.market.impl.rest.discount;

import com.jic.market.common.exception.MarketErrorCodeEnum;
import com.jic.market.common.exception.MarketException;
import com.jic.market.common.util.Money;
import com.jic.market.entity.DiscountOrderDetail;
import com.jic.market.enums.DiscountAmountServiceOperateEnum;
import com.jic.market.enums.DiscountOrderStatusEnum;
import com.jic.market.enums.FrontPromotionTypeEnum;
import com.jic.market.enums.MutuallyExclusiveTypeEnum;
import com.jic.market.impl.rest.discount.model.ConditionDiscountModel;
import com.jic.market.impl.rest.discount.model.DiscountOrderModel;
import com.jic.market.impl.rest.discount.model.GoodsDetailModel;
import com.jic.market.mapper.DiscountOrderDetailMapper;
import com.jic.market.request.rest.discount.*;
import com.jic.market.response.rest.coupon.QueryCouponPersonResponse;
import com.jic.market.response.rest.discount.ConditionDiscount;
import com.jic.market.response.rest.discount.DiscountQueryResponse;
import com.jic.market.response.rest.discount.GoodsDetail;
import com.jic.market.service.rest.discount.DiscountModelService;
import com.jic.market.service.rest.discount.DiscountProcesserService;
import com.jic.market.service.rest.discount.DiscountService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author yinhaijun
 * @date: 2020/4/27
 */
@Service
public class DiscountServiceImpl implements DiscountService {
    @Autowired
    private DiscountModelService discountModelService;
    @Autowired
    private DiscountOrderDetailMapper discountOrderDetailMapper;
    @Autowired
    private DiscountProcesserService discountProcesserService;

    @Override
    public List<QueryCouponPersonResponse> queryCoupon(DiscountQueryRequest request) {
        List<QueryCouponPersonResponse> responseList = new ArrayList<>();
        // 单品活动
        Map<String, GoodsDetailModel> goodsDetailModelMap = discountModelService.buildSingle(request.getPromotionGoodsList(), FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        discountProcesserService.processorPromotion(goodsDetailModelMap, request, request.getThirdUserId(), DiscountAmountServiceOperateEnum.COUPON_QUERY);

        // 多品活动
        List<ConditionDiscountModel> conditionDiscountModelList = discountModelService.buildCondition(goodsDetailModelMap, request, FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.COUPON_QUERY);

        // 优惠劵
        Map<MutuallyExclusiveTypeEnum, List<ConditionDiscountModel>> couponDiscountModelListMap = discountModelService.buildCoupon(goodsDetailModelMap, request.getCouponCodeInfoList());
        if(null != couponDiscountModelListMap && !couponDiscountModelListMap.isEmpty()){
            couponDiscountModelListMap.forEach((separateTypeEnum, couponDiscountModelList)->{
                discountProcesserService.couponQuery(couponDiscountModelList, goodsDetailModelMap, request);
                for(ConditionDiscountModel conditionDiscountModel : couponDiscountModelList){
                    responseList.add(conditionDiscountModel.getCouponInfo());
                }
            });
        }
        return responseList;
    }

    @Override
    public DiscountQueryResponse queryShoppingCartDiscount(@Valid DiscountQueryRequest request) {
        request.check();
        // 单品活动
        Map<String, GoodsDetailModel> goodsDetailModelMap = discountModelService.buildSingle(request.getPromotionGoodsList(), FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        discountProcesserService.processorPromotion(goodsDetailModelMap, request, request.getThirdUserId(), DiscountAmountServiceOperateEnum.SHOPPING_CART_QUERY);

        // 多品活动
        List<ConditionDiscountModel> conditionDiscountModelList = discountModelService.buildCondition(goodsDetailModelMap, request, FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.SHOPPING_CART_QUERY);

        List<ConditionDiscountModel> resultDiscountModelList = new ArrayList<>();
        resultDiscountModelList.addAll(conditionDiscountModelList);
        // 优惠劵
        Map<MutuallyExclusiveTypeEnum, List<ConditionDiscountModel>> couponDiscountModelListMap = discountModelService.buildCoupon(goodsDetailModelMap, request.getCouponCodeInfoList());
        couponDiscountModelListMap.forEach((separateTypeEnum, couponDiscountModelList)->{
            discountProcesserService.couponProcess(couponDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.SETTLEMENT_QUERY);
            if(null != couponDiscountModelList){
                resultDiscountModelList.addAll(couponDiscountModelList);
            }
        });
        // 返回
        DiscountQueryResponse discountQueryResponse = getDiscountQueryResponse(goodsDetailModelMap, resultDiscountModelList);
        return discountQueryResponse;
    }

    @Override
    public DiscountQueryResponse querySettlement(DiscountQueryRequest request) {
        // 参数校验
        request.check();
        // 单品活动模型构造
        Map<String, GoodsDetailModel> goodsDetailModelMap = discountModelService.buildSingle(request.getPromotionGoodsList(), FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        // 处理单品活动
        discountProcesserService.processorPromotion(goodsDetailModelMap, request, request.getThirdUserId(), DiscountAmountServiceOperateEnum.SETTLEMENT_QUERY);

        // 多品活动模型构造
        List<ConditionDiscountModel> conditionDiscountModelList = discountModelService.buildCondition(goodsDetailModelMap, request, FrontPromotionTypeEnum.getByCode(request.getFrontPromotionType()));
        // 处理多品活动
        discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.SETTLEMENT_QUERY);
        List<ConditionDiscountModel> resultDiscountModelList = new ArrayList<>();
        resultDiscountModelList.addAll(conditionDiscountModelList);
        // 优惠劵模型构造
        Map<MutuallyExclusiveTypeEnum, List<ConditionDiscountModel>> couponDiscountModelListMap = discountModelService.buildCoupon(goodsDetailModelMap, request.getCouponCodeInfoList());
        // 处理优惠券活动
        couponDiscountModelListMap.forEach((separateTypeEnum, couponDiscountModelList)->{
            discountProcesserService.couponProcess(couponDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.SETTLEMENT_QUERY);
            if(null != couponDiscountModelList){
                resultDiscountModelList.addAll(couponDiscountModelList);
            }
        });
        // 返回
        DiscountQueryResponse discountQueryResponse = getDiscountQueryResponse(goodsDetailModelMap, resultDiscountModelList);
        return discountQueryResponse;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized List<DiscountQueryResponse> create(DiscountOrderCreateRequest request) {
        List<DiscountQueryResponse> discountQueryResponseList = new ArrayList<>();
        List<DiscountSubOrderRequest> discountSubOrderRequestList = request.getDiscountSubOrderRequestList();
        // 循环处理子订单
        for(DiscountSubOrderRequest discountSubOrderRequest: discountSubOrderRequestList){
            // 重复校验
            DiscountOrderDetail discountOrderDetailQ = new DiscountOrderDetail();
            discountOrderDetailQ.setOrderNo(discountSubOrderRequest.getOrderNo());
            List<DiscountOrderDetail> discountOrderDetailList = discountOrderDetailMapper.query(discountOrderDetailQ);
            if(null != discountOrderDetailList && !discountOrderDetailList.isEmpty()){
                throw new MarketException(MarketErrorCodeEnum.PARAM_ERROR, "重复的订单号");
            }
            // 构建初始订单模型
            DiscountOrderModel discountOrderModel = discountModelService.buildDiscountOrderModel(discountSubOrderRequest);
            discountOrderModel.setOrderCreateTime(request.getOrderCreateTime());
            discountOrderModel.setParentOrderNo(request.getParentOrderNo());
            discountOrderModel.setThirdUserId(request.getThirdUserId());
            discountOrderModel.setDiscountOrderStatus(DiscountOrderStatusEnum.CREATE);

            // 单品活动
            Map<String, GoodsDetailModel> goodsDetailModelMap = discountOrderModel.getGoodsDetailModelMap();
            discountProcesserService.processorPromotion(goodsDetailModelMap, discountSubOrderRequest, request.getThirdUserId(), DiscountAmountServiceOperateEnum.CREATE);

            // 多品活动包括优惠券
            List<ConditionDiscountModel> conditionDiscountModelList = discountOrderModel.getConditionDiscountModelList();
            if(null != conditionDiscountModelList && !conditionDiscountModelList.isEmpty()){
                discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.CREATE);
            }
            // 保存数据
            discountModelService.save(discountOrderModel);
            DiscountQueryResponse discountQueryResponse = getDiscountQueryResponse(goodsDetailModelMap, conditionDiscountModelList);
            discountQueryResponseList.add(discountQueryResponse);
        }
        return discountQueryResponseList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized Integer pay(DiscountOrderPayRequest request) {
        DiscountOrderModel discountOrderModel = discountModelService.load(request.getOrderNo());
        if(null == discountOrderModel){
            throw new MarketException(MarketErrorCodeEnum.PARAM_ERROR, "订单不存在");
        }

        discountOrderModel.setDiscountOrderStatus(DiscountOrderStatusEnum.PAY);
        // 单品
        Map<String, GoodsDetailModel> goodsDetailModelMap = discountOrderModel.getGoodsDetailModelMap();
        discountProcesserService.processorPromotion(goodsDetailModelMap, request, discountOrderModel.getThirdUserId(), DiscountAmountServiceOperateEnum.PAY);


        // 多品
        List<ConditionDiscountModel> conditionDiscountModelList = discountOrderModel.getConditionDiscountModelList();
        discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.PAY);

        discountOrderModel.setPayAmount(request.getPayAmount());
        discountOrderModel.setOrderPayTime(request.getOrderPayTime());
        discountModelService.save(discountOrderModel);
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized DiscountQueryResponse cancel(DiscountCancelRequest request) {
        DiscountOrderModel discountOrderModel = discountModelService.load(request.getOrderNo());
        if(null == discountOrderModel){
            throw new MarketException(MarketErrorCodeEnum.PARAM_ERROR, "订单不存在");
        }

        // 单品
        Map<String, GoodsDetailModel> goodsDetailModelMap = discountOrderModel.getGoodsDetailModelMap();
        discountProcesserService.processorPromotion(goodsDetailModelMap, request, discountOrderModel.getThirdUserId(), DiscountAmountServiceOperateEnum.REFUND);

        // 多品
        discountOrderModel.setDiscountOrderStatus(DiscountOrderStatusEnum.REFUND);
        List<ConditionDiscountModel> conditionDiscountModelList = discountOrderModel.getConditionDiscountModelList();
        discountProcesserService.processorPromotion(conditionDiscountModelList, goodsDetailModelMap, request, DiscountAmountServiceOperateEnum.REFUND);

        discountModelService.save(discountOrderModel);
        DiscountQueryResponse discountQueryResponse = getDiscountQueryResponse(goodsDetailModelMap, conditionDiscountModelList);
        return discountQueryResponse;
    }

    private DiscountQueryResponse getDiscountQueryResponse(Map<String, GoodsDetailModel> goodsDetailModelMap, List<ConditionDiscountModel> conditionDiscountModelList) {
        DiscountQueryResponse discountQueryResponse = new DiscountQueryResponse();
        AtomicReference<BigDecimal> discountTotalAmount = new AtomicReference(BigDecimal.ZERO);
        AtomicReference<BigDecimal> discountFreightAmount = new AtomicReference(BigDecimal.ZERO);

        List<ConditionDiscount> conditionDiscountList = new ArrayList<>();
        if(null != conditionDiscountModelList && !conditionDiscountModelList.isEmpty()){
            for(ConditionDiscountModel conditionDiscountModel : conditionDiscountModelList){
                ConditionDiscount conditionDiscount = buildConditionDiscount(conditionDiscountModel);
                conditionDiscountList.add(conditionDiscount);
                discountTotalAmount.set(Money.add(discountTotalAmount.get(), conditionDiscountModel.getPromotionDiscountTotalAmount()));
            }
        }
        discountQueryResponse.setConditionDiscountList(conditionDiscountList);
        List<GoodsDetail> goodsDetailList = new ArrayList<>();
        if(null != goodsDetailModelMap && !goodsDetailModelMap.isEmpty()){
            goodsDetailModelMap.forEach((thirdSkuId, goodsDetailModel)->{
                GoodsDetail goodsDetail = new GoodsDetail();
                BeanUtils.copyProperties(goodsDetailModel, goodsDetail);
                goodsDetail.setSkillTimeList(goodsDetailModel.getSkillTimeList());
                if(!StringUtils.isEmpty(goodsDetailModel.getPromotionCode())){
                    goodsDetail.setPromotionCode(goodsDetailModel.getPromotionCode());
                    goodsDetail.setFrontPromotionType(goodsDetailModel.getFrontPromotionTypeEnum().getCode());
                    goodsDetail.setFrontPromotionTypeName(goodsDetailModel.getFrontPromotionTypeEnum().getMessage());
                    goodsDetail.setPromotionDiscountTotalAmount(goodsDetailModel.getPromotionDiscountTotalAmount());
                }
                goodsDetailList.add(goodsDetail);
                discountTotalAmount.set(Money.add(discountTotalAmount.get(), goodsDetailModel.getPromotionDiscountTotalAmount()));
                discountFreightAmount.set(Money.add(discountFreightAmount.get(), goodsDetailModel.getPromotionDiscountFreightAmount()));
            });
        }
        discountQueryResponse.setGoodsDetailList(goodsDetailList);
        discountQueryResponse.setDiscountTotalAmount(discountTotalAmount.get());
        discountQueryResponse.setDiscountFreightAmount(discountFreightAmount.get());
        return discountQueryResponse;
    }

    private ConditionDiscount buildConditionDiscount(ConditionDiscountModel conditionDiscountModel) {
        ConditionDiscount conditionDiscount = new ConditionDiscount();
        conditionDiscount.setPromotionCode(conditionDiscountModel.getPromotionCode());
        if(null != conditionDiscountModel.getFrontPromotionTypeEnum()){
            conditionDiscount.setFrontPromotionType(conditionDiscountModel.getFrontPromotionTypeEnum().getCode());
            conditionDiscount.setFrontPromotionTypeName(conditionDiscountModel.getFrontPromotionTypeEnum().getMessage());
        }
        conditionDiscount.setPromotionDiscountTotalAmount(conditionDiscountModel.getPromotionDiscountTotalAmount());
        conditionDiscount.setPromotionDiscountFreightAmount(conditionDiscountModel.getPromotionDiscountFreightAmount());
        conditionDiscount.setThirdSkuIdList(conditionDiscountModel.getThirdSkuIdList());
        conditionDiscount.setGiftDetailList(conditionDiscountModel.getGiftDetailList());
        conditionDiscount.setCouponInfo(conditionDiscountModel.getCouponInfo());
        return conditionDiscount;
    }

}
